# -*- coding: utf-8 -*-
import threading
import pyqtgraph as pg
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication
import sys
import pandas as pd
from pyqtgraph.exporters import ImageExporter
from pyqtgraph.icons import getGraphIcon
from PyQt5.QtCore import QPoint
import pyqtgraph.functions as fn
from pyqtgraph.graphicsItems.ScatterPlotItem import drawSymbol

from src.sharedSrc import getSetting, rHEX


class WaferBlock(pg.ItemSample):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.wafer_map = None  # Reference to the WaferMap instance

    def paint(self, p, *args):
        opts = self.item.opts
        visible = self.item.isVisible()

        if not visible:
            icon = getGraphIcon("invisibleEye")
            p.drawPixmap(QPoint(1, 1), icon.pixmap(18, 18))
            return

        symbol = opts.get('symbol', None)
        if symbol is not None:
            p.translate(10, 15)
            drawSymbol(p, symbol, 20, fn.mkPen(opts['pen']),
                       fn.mkBrush(opts['brush']))


class WaferMap(pg.GraphicsView):
    def __init__(self):
        super().__init__()
        self.text_items = []
        self.plotlayout = pg.GraphicsLayout()
        self.setCentralWidget(self.plotlayout)
        self.view_list = []
        self.setBackground('white')
        self.settings = getSetting()

    def setWaferData(self, wafer_data: dict, file_name: str = '') -> None:
        if len(wafer_data) == 0:
            return
        self.sColor = self.settings.sColor
        wafer_view = pg.ViewBox()
        self.pitem = pg.PlotItem(viewBox=wafer_view)

        legend = self.pitem.addLegend(offset=(40, 5), verSpacing=5, labelTextSize="15pt")
        xy_data = wafer_data["Data"]
        sorted_keys = sorted(xy_data.keys())

        for num in sorted_keys:
            xy_dict = xy_data[num]
            color = self.sColor.get(str(num), rHEX())
            legend_string = f"SBIN {num}"
            tip_func = f"XY: ({{x:.0f}}, {{y:.0f}})\nSBIN {num}".format

            self.spi = pg.ScatterPlotItem(
                symbol="s",
                pen=None,
                size=0.95,
                pxMode=False,
                hoverable=True,
                hoverPen=pg.mkPen('r', width=4),
                hoverSize=1,
                tip=tip_func,
                name=None,
            )
            self.spi.addPoints(x=xy_dict["x"], y=xy_dict["y"], brush=color)
            self.pitem.addItem(self.spi)
            wafer_block = WaferBlock(self.spi)
            wafer_block.wafer_map = self  # Set reference to WaferMap instance
            legend.addItem(wafer_block, legend_string)

            self.measure = xy_dict['Bin']
            self.text_items = [(x, y, self.measure[f"{x} {y}"]) for x, y in zip(xy_dict["x"], xy_dict["y"])]

            if self.settings.parametric_sbin:
                text_items = [(x, y, self.measure[f"{x} {y}"]) for x, y in zip(xy_dict["x"], xy_dict["y"])]

                font = QFont()
                font.setPointSize(self.settings.sfont_size)  # Set the font size to 12, for example
                for x, y, text in text_items:
                    text_item = pg.TextItem(text=text, anchor=(0.5, 0.5), color="#000000")
                    text_item.setPos(x, y)
                    text_item.setFont(font)
                    self.pitem.addItem(text_item)

        (ratio, die_size, invert_x, invert_y) = wafer_data["Info"]
        x_max, x_min, y_max, y_min = wafer_data["Bounds"]
        wafer_view.setLimits(xMin=x_min - 25, xMax=x_max + 25,
                             yMin=y_min - 25, yMax=y_max + 25,
                             maxXRange=(x_max - x_min + 50),
                             maxYRange=(y_max - y_min + 50),
                             minXRange=2, minYRange=2)
        wafer_view.setRange(xRange=(x_min - 15, x_max + 5),
                            yRange=(y_min - 15, y_max + 5),
                            disableAutoRange=False)
        wafer_view.setAspectLocked(lock=True, ratio=ratio)
        if self.settings.wafer_invert[self.settings.wafer_origin_index]['x']:
            wafer_view.invertX(True)
        if self.settings.wafer_invert[self.settings.wafer_origin_index]['y']:
            wafer_view.invertY(True)

        if die_size:
            die_size_text = pg.LabelItem(die_size, size="12pt", color="#000000", anchor=(0, 0))
            die_size_text.setParentItem(self.pitem)
            die_size_text.anchor(itemPos=(0, 0), parentPos=(0, 0), offset=(30, 30))

        self.plotlayout.addItem(self.pitem, row=1, col=0, rowspan=1, colspan=2)
        self.view_list.append(wafer_view)
        if file_name != '':
            self.save_plot(file_name)

    def add_text_items(self):
        for x, y, text in self.text_items:
            text_item = pg.TextItem(text=text, anchor=(0.5, 0.5), color="#000000")
            text_item.setPos(x, y)
            self.pitem.addItem(text_item)

    def remove_text_items(self):
        for item in self.pitem.items:
            if isinstance(item, pg.TextItem):
                self.pitem.removeItem(item)

    def save_plot(self, filename: str) -> None:
        self.resize(2100, 1200)  # Example size
        self.plotlayout.resize(2100, 1200)
        exporter = ImageExporter(self.plotlayout.scene())
        exporter.export(filename)

    def func_t1(self, items_to_add):
        for item in items_to_add:
            self.pitem.addItem(item)

def main():
    df = pd.read_csv(r"D:\dataset\new\auto_20240709-233354_datalog_20240710070313.csv", dtype=str, low_memory=False)
    measure_list = [col for col in df.columns if 'Measure' in col]

    x_coord_df = df[df['Force'] == 'XCoord']
    y_coord_df = df[df['Force'] == 'YCoord']
    bin_df = df[df['Force'] == 'Cate']
    data = {}

    if len(measure_list):
        value = bin_df[measure_list[0]].astype(int).iloc[0]
        x_max = value
        x_min = value
        y_max = value
        y_min = value
    else:
        return data
    for measure in measure_list:
        x_values = x_coord_df[measure].astype(int).values[0]
        y_values = y_coord_df[measure].astype(int).values[0]
        bin_values = bin_df[measure].iloc[0]  # Assuming Bin values are consistent

        if x_min > x_values:
            x_min = x_values
        elif x_max < x_values:
            x_max = x_values
        if y_min > y_values:
            y_min = y_values
        elif y_max < y_values:
            y_max = y_values
        if bin_values in data.keys():
            data[bin_values]['x'].append(x_values)
            data[bin_values]['y'].append(y_values)
            data[bin_values]['Bin'].update({f"{x_values} {y_values}": bin_values})
        else:
            data[bin_values] = {
                'x': [x_values],
                'y': [y_values],
                'Bin': {f"{x_values} {y_values}": bin_values}
            }

    sample_wafer_data = {
        "Data": data,
        "Info": (1.0, "200um", False, False),
        "Bounds": (x_max, x_min, y_max, y_min)
    }
    app = QApplication(sys.argv)
    wafer_map = WaferMap()
    wafer_map.setWaferData(sample_wafer_data)
    wafer_map.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
